// 教师端 WebSocket 工具（增强版）：重连、心跳、持久监听
// 用法：ws.connect({ url, userId, userType: 2 })；ws.onMessage(fn) 注册监听；ws.removeListener(fn) 取消

const ws = {
  socket: null,
  url: '',
  userId: null,
  userType: 2,
  isOpen: false,
  reconnectAttempts: 0,
  maxReconnectDelayMs: 15000,
  heartbeatTimer: null,
  reconnectTimer: null,
  shouldReconnect: true,
  listeners: [],

  connect({ url, userId, userType = 2 }) {
    this.url = url;
    this.userId = userId;
    this.userType = userType;
    this.shouldReconnect = true;
    if (this.reconnectTimer) { try { clearTimeout(this.reconnectTimer); } catch (_) {} this.reconnectTimer = null; }

    const full = `${url}?userId=${userId}&userType=${userType}`;
    try {
      // 若已有连接且已打开并参数一致，则跳过重连
      if (this.socket && this.isOpen) {
        try {
          const currentUrl = this.socket?.url || '';
          if (currentUrl === full) {
            return; // 复用现有连接
          }
        } catch (_) {}
        try { this.socket.close(); } catch (_) {}
        this.socket = null;
      }
      this.isOpen = false;

      const socket = wx.connectSocket({ url: full });
      this.socket = socket;

      socket.onOpen(() => {
        console.log('[WS] open', full);
        this.isOpen = true;
        this.reconnectAttempts = 0;
        this.startHeartbeat();
      });

      socket.onError((e) => {
        console.warn('[WS] error', e);
        this.isOpen = false;
        this.stopHeartbeat();
        if (this.shouldReconnect) this.scheduleReconnect();
      });

      socket.onClose(() => {
        console.log('[WS] close');
        this.isOpen = false;
        this.stopHeartbeat();
        if (this.shouldReconnect) this.scheduleReconnect();
      });

      socket.onMessage((evt) => {
        let payload = evt.data;
        try { payload = JSON.parse(evt.data); } catch (_) {}
        // 分发到所有监听者
        (this.listeners || []).forEach(fn => {
          try { fn(payload); } catch (_) {}
        });
      });
    } catch (err) {
      console.warn('[WS] connect failed', err);
      this.scheduleReconnect();
    }
  },

  onMessage(fn) {
    if (typeof fn === 'function') {
      this.listeners.push(fn);
    }
  },

  removeListener(fn) {
    this.listeners = (this.listeners || []).filter(cb => cb !== fn);
  },

  send(data) {
    if (!this.socket) return;
    try {
      this.socket.send({ data: typeof data === 'string' ? data : JSON.stringify(data) });
    } catch (e) {
      console.warn('[WS] send failed', e);
    }
  },

  close() {
    this.stopHeartbeat();
    this.shouldReconnect = false;
    if (this.reconnectTimer) { try { clearTimeout(this.reconnectTimer); } catch (_) {} this.reconnectTimer = null; }
    if (!this.socket) return;
    try { this.socket.close(); } catch (_) {}
    this.socket = null;
    this.isOpen = false;
  },

  startHeartbeat() {
    this.stopHeartbeat();
    // 30s 心跳防断开
    this.heartbeatTimer = setInterval(() => {
      try {
        if (this.socket && this.isOpen) {
          this.socket.send({ data: 'PING' });
        }
      } catch (_) {}
    }, 30000);
  },

  stopHeartbeat() {
    if (this.heartbeatTimer) {
      try { clearInterval(this.heartbeatTimer); } catch (_) {}
      this.heartbeatTimer = null;
    }
  },

  scheduleReconnect() {
    if (!this.shouldReconnect) return;
    if (this.reconnectTimer) return; // 已安排重连
    // 指数退避，最高 15s
    const attempt = Math.min(this.reconnectAttempts + 1, 8);
    this.reconnectAttempts = attempt;
    const delay = Math.min(1000 * Math.pow(1.5, attempt), this.maxReconnectDelayMs);
    console.log(`[WS] reconnect in ${Math.round(delay)}ms (attempt ${attempt})`);
    this.reconnectTimer = setTimeout(() => {
      this.reconnectTimer = null;
      try {
        if (!this.url || !this.userId) return;
        this.connect({ url: this.url, userId: this.userId, userType: this.userType });
      } catch (_) {}
    }, delay);
  }
};

module.exports = ws;